package pyip.lib.javalearn.io;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.zip.CRC32;

/**
 * 几种读写文件方式的简单效率对比<br>
 * 1. channel(内存映射文件)<br>
 * JDK1.4版本引入了java.nio包，对文件流进行读写操作，提供无阻塞模式(FileChannel无法设置为非阻塞模式，它总是运行在阻塞模式下)。<br>
 * 同时也提供了一种高效率的文件读写模式--内存映射文件，主要用到下面类：<br>
 * java.nio.MappedByteBuffer;<br>
 * java.nio.channels.FileChannel;<br>
 * FileInputStream.getChannel, FileOutputStream.getChannel, RandomAccessFile.getChannel。<br>
 * <br>
 * 内存映射文件的原理：首先将外存文件某个区域块映射到内存中的一块连续区域，被当成一个字节数组进行处理，<br>
 * 读写操作直接对内存进行操作，而后再将内存区域重新映射到外存文件，节省了中间频繁的对外存进行读写的时间，大大降低了读写时间。<br>
 * <br>
 * 2. random access<br>
 * <br>
 * 3. file input stream<br>
 * <br>
 * 4. buffered file input stream<br>
 * <br>
 * 在处理大文件时，如果利用普通的FileInputStream 或者FileOutputStream 抑或RandomAccessFile 来进行频繁的读写操作，都将导致进程因频繁读写外存而降低速度。<br>
 * @author yepeng
 * @date 2015年8月26日
 */
public class ReadFileTest {

    public static void main(String[] args) throws Exception {
        String filename = "d:\\Program Files\\Java\\jdk1.6.0_45\\jre\\lib\\rt.jar";

        try (RandomAccessFile raf = new RandomAccessFile(filename, "r");) {
            System.out.println("read by byte");
            System.out.println("rt.jar, " + raf.length() + "B(" + raf.length() / 1024 + "K)");
        }

        long crc = 0;
        long s1 = System.currentTimeMillis();
        crc = mapFile(filename);
        long e1 = System.currentTimeMillis();
        System.out.println("map(channel)\tcrc: " + crc + " time(ms): " + (e1 - s1));

        long s2 = System.currentTimeMillis();
        crc = randomFile(filename);
        long e2 = System.currentTimeMillis();
        System.out.println("randomAccess\tcrc: " + crc + " time(ms): " + (e2 - s2));

        long s3 = System.currentTimeMillis();
        crc = inputStreamFile(filename);
        long e3 = System.currentTimeMillis();
        System.out.println("inputStream\tcrc: " + crc + " time(ms): " + (e3 - s3));

        long s4 = System.currentTimeMillis();
        crc = bufferedInputStreamFile(filename);
        long e4 = System.currentTimeMillis();
        System.out.println("buffered\tcrc: " + crc + " time(ms): " + (e4 - s4));
    }

    private static long mapFile(String filename) throws IOException {
        try (FileInputStream fin = new FileInputStream(filename); FileChannel channel = fin.getChannel()) {
            // 计算crc校验码，crc校验码可以检验文件内容是否一致
            CRC32 crc = new CRC32();
            long length = channel.size();
            // 内存映射文件
            MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, length);
            for (int p = 0; p < length; p++) {
                int c = buffer.get(p);
                crc.update(c);
            }
            channel.close();
            return crc.getValue();
        }
    }

    private static long randomFile(String filename) throws Exception {
        try (RandomAccessFile raf = new RandomAccessFile(filename, "r")) {
            long length = raf.length();
            CRC32 crc = new CRC32();
            for (long p = 0; p < length; p++) {
                raf.seek(p);
                int c = raf.readByte();
                crc.update(c);
            }
            return crc.getValue();
        }
    }

    private static long inputStreamFile(String filename) throws Exception {
        try (InputStream fin = new FileInputStream(filename)) {
            CRC32 crc = new CRC32();
            int c;
            while ((c = fin.read()) != -1) {
                crc.update(c);
            }
            return crc.getValue();
        }
    }

    private static long bufferedInputStreamFile(String filename) throws Exception {
        try (InputStream in = new BufferedInputStream(new FileInputStream(filename))) {
            CRC32 crc = new CRC32();
            int c;
            while ((c = in.read()) != -1) {
                crc.update(c);
            }
            return crc.getValue();
        }
    }
}